home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-13 / emac16ds.zip / MINTPRIM.ASM < prev    next >
Assembly Source File  |  1992-08-01  |  36KB  |  1,576 lines

  1. ;History:1261,1
  2. ;Thu Mar 26 21:42:34 1992 Improve ct so that it returns file size and attribute info.
  3. ;Wed Aug 14 23:02:57 1991 Add env.SCREEN to the list of strings created by #(ev).
  4. ;Sun Jun 16 23:52:43 1991 Change #(mp) so that it preserves the "no sgaps marker" if no matches were found.
  5. ;Mon May 06 00:53:33 1991 experiment with sgap markers.
  6. ;Sun May 05 19:42:10 1991 add #(hk,...)
  7. ;Sat May 04 22:31:00 1991 added #(!=)
  8. ;Mon Apr 16 22:41:11 1990 Add "Read Only" error to write_error.
  9. ;Thu Feb 22 23:32:17 1990 add logical operators: and, or, xor.
  10. ;Tue Feb 13 19:24:24 1990 add 'Read Only' to the list of read_errors.
  11. ;Thu Sep 14 23:38:27 1989 when dealing with nonexistent strings, remember whether it was active or not.
  12. ;Tue Sep 12 23:52:46 1989 gs_prim now calls dflt if the real string can't be found.
  13. ;Sun Jun 25 23:55:33 1989 try a faster string_search
  14. ;11-04-88 00:39:35 remove #(dt) and #(tm) and put in #(ct).
  15. ;10-24-88 23:08:30 change #(si) so that it maps multiple characters.
  16. ;10-01-88 17:31:20 get_number would look too far for a minus sign.
  17. ;09-18-88 23:13:15 add "string index", si_prim.
  18. ;05-15-88 20:04:09 Remove reference to non-existent buffer_free1 [kdb]
  19. ;04-19-88 23:01:23 in ll_prim, protect the data buffer by setting data_topbot.
  20. ;04-19-88 20:16:30 ll_prim didn't work with a shortage of memory.
  21. ;03-27-88 13:40:14 change getarg_filename so that it returns zr on empty filenames.
  22. ;03-14-88 23:26:08 add fullpath under dos 3.0.
  23. ;12-07-87 23:14:20 make mp_prim discard sgaps after making parameters.
  24. ;11-10-87 21:43:34 make a marker at the end of the bufseg() definition.
  25. ;09-06-87 23:27:39 in ll_prim, we're all done if we hit eof.
  26. ;09-06-87 23:07:39 use a big buffer to read libraries in.
  27. ;07-10-87 00:13:50 get rid of duplicate copy of bc_prim.
  28.     page    ,132
  29.  
  30.     .xlist
  31.     include    emacs.def
  32.     include    mintform.def
  33.     include    mint.def
  34.     include findfile.def
  35.     include    memory.def
  36.  
  37. data    segment byte public
  38.     extrn    data_bottop: word
  39.     extrn    data_topbot: word
  40.  
  41.     extrn    fbgn:    word
  42.     extrn    fend:    word
  43.  
  44.     extrn    filename: byte, filename2: byte
  45.  
  46. size_buf    dw    ?
  47.  
  48.     public    save_stack
  49. save_stack    dw    ?
  50.  
  51.     public    read_errors
  52. read_errors    dw    read_error_1
  53.     dw    read_error_2
  54.     dw    read_error_3
  55.     dw    read_error_4
  56.     dw    read_error_5
  57.     dw    read_error_6
  58.  
  59.     public    write_errors
  60. write_errors    dw    write_error_1
  61.     dw    write_error_2
  62.     dw    write_error_3
  63.     dw    write_error_4
  64.     dw    write_error_5
  65.  
  66. read_error_1    label    byte
  67. read_error_2    db    'File too large'
  68. read_error_3    db    'File not found'
  69. read_error_4    db    'End of file'
  70. read_error_5    db    'Read Only'
  71. read_error_6    label    byte
  72.  
  73. write_error_1    label    byte
  74. write_error_2    db    'Disk full'
  75. write_error_3    db    'Directory full or bad filename'
  76. write_error_4    db    'Read Only'
  77. write_error_5    label    byte
  78.  
  79.  
  80. runline_name    label    byte
  81. environ_name    db    'env.'
  82. environ_name_len    equ    $-environ_name
  83.         db    'RUNLINE'
  84. runline_len    equ    $-environ_name
  85.  
  86. switchar_name    db    'env.SWITCHAR'
  87. switchar_len    equ    $-switchar_name
  88.  
  89. fullpath_name    db    'env.FULLPATH'
  90. fullpath_len    equ    $-fullpath_name
  91.  
  92. screen_name    db    'env.SCREEN'
  93. screen_len    equ    $-screen_name
  94.  
  95. dflta_name    db    'dflta'
  96. dflta_len    equ    $-dflta_name
  97.  
  98. dfltn_name    db    'dfltn'
  99. dfltn_len    equ    $-dfltn_name
  100.  
  101. form_prefix_len    dw    ?        ;for use by ln prim
  102. form_prefix_ptr    dw    ?        ;...
  103.  
  104. out_of_memory_msg    db    'Not enough memory.$'
  105.  
  106. break_state    db    ?        ;=state of break checking flag.
  107.  
  108.     extrn    stackp: byte
  109.     extrn    max_screen_line: byte
  110.  
  111.     public    phd_seg
  112. phd_seg    dw    ?
  113.  
  114. day_of_week    db    'Sun Mon Tue Wed Thu Fri Sat     '
  115. months        db    'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec '
  116.  
  117. data    ends
  118.  
  119. code    segment byte public
  120.     assume    cs:code, ds:data, es:data
  121.  
  122.     extrn    buffer_free: near
  123.  
  124. ;starting address of program.
  125. init:
  126.     mov    ax,data
  127.     mov    ds,ax
  128.     mov    bx,es:[2]        ;get available paragraphs.
  129.     mov    phd_seg,es
  130.     mov    es,ax
  131.     cli
  132.     mov    ss,ax
  133.     mov    sp,offset stackp
  134.     sti
  135.  
  136.     mov    dx,bx
  137.     sub    dx,ax            ;compute memory between data and end.
  138.     cmp    dx,1000h        ;more than 64k?
  139.     jb    init_exit        ;no - not enough memory.
  140.     add    ax,1000h        ;start buffers at the next segment up.
  141. ;enter with ax=>first paragraph of available memory, bx=> first paragraph of
  142. ;  unavailable memory.
  143.     push    ax
  144.     push    bx
  145.     call    init_entry        ;init the machine-dependent code
  146.     pop    bx
  147.     pop    ax
  148.     call    init_all_buffers
  149.     jc    init_exit_uninit    ;no memory.
  150.     call    init_screen        ;initialize redisplay.
  151.     call    pick_init        ;initialize the mouse.
  152.  
  153.     push    ds            ;set the fatal error address.
  154.     push    cs
  155.     pop    ds
  156.     mov    dx,offset abort_fatal
  157.     mov    ax,2524h
  158.     int    21h
  159.     pop    ds
  160.  
  161.     mov    ax,33h*256+0        ;get the break state.
  162.     int    21h
  163.     mov    break_state,dl
  164.     mov    ax,33h*256+1        ;turn break checking off.
  165.     mov    dl,0
  166.     int    21h
  167.  
  168.     jmp    init_ids_first
  169. init_exit_uninit:
  170.     call    uninit_exit
  171. init_exit:
  172.     mov    dx,offset out_of_memory_msg
  173.     mov    ah,9
  174.     int    21h
  175.     mov    ax,4c01h
  176.     int    21h            ;halt because of no memory.
  177.  
  178. ;the following externs are in 'buffers'
  179.     extrn    init_all_buffers: near
  180.  
  181. ;the following externs are in 'redisp'
  182.     extrn    init_screen: near
  183.  
  184. ;the following externs are in 'pick'
  185.     extrn    pick_init: near
  186.  
  187.     extrn    init_ids_first: near    ;start mint interpreter
  188.     extrn    init_ids: near        ;restart mint interpreter
  189.     extrn    abort_fatal: near    ;fatal error handler
  190.     extrn    read_chars: near    ;read chars off the original screen.
  191.  
  192. ;the following externs are in 'mintprim'
  193.     extrn    init_forms: near
  194.  
  195.  
  196. ;The following two externs init and uninit anything that's machine specific.
  197.     extrn    init_entry: near
  198.     extrn    uninit_exit: near
  199.  
  200.     extrn    return_form: near
  201. ;return_form updates the form pointer and jumps to return_tos.
  202. ;Enter with ds:bx ->form, cx=unused chars.
  203.  
  204.     extrn    return_null: near
  205.  
  206.     extrn    make_active: near
  207. ;make_active forces the function to be executed in active mode, and returns
  208. ;    zr if the function already was active.
  209.  
  210.     extrn    return_arg: near
  211. ;return_arg returns the argument whose number is given in cx.
  212.  
  213.     extrn    return_arg_active: near
  214. ;return_arg_active returns the argument whose number is given in cx, and makes
  215. ;    it active.
  216.  
  217.     extrn    return_string: near
  218. ;return_string returns the ALth string out of the table pointed to by bx.
  219.  
  220.     extrn    return_sicx: near
  221. ;return_sicx returns the string pointed to by si.  The length of the
  222. ;    string is given in cx.
  223.  
  224.     extrn    return_tos: near
  225. ;return_tos returns the string pointed to by the top of the stack.
  226. ;    The length of the string is the difference between di and the
  227. ;    beginning of the stirng.
  228.  
  229.     extrn    nomem: near
  230.  
  231. ;primitives here
  232.  
  233. hl_prim:
  234.     call    get_decimal_arg1    ;get the return code.
  235.     push    ax
  236.     mov    ax,33h*256+1        ;set the break state.
  237.     mov    dl,break_state
  238.     int    21h
  239.     call    uninit_exit
  240.     pop    ax
  241.     mov    ah,4ch
  242.     int    21h
  243.  
  244.  
  245. eq_prim:
  246.     call    getarg1        ;get the first argument
  247.     mov    dx,cx        ;save size of first argument
  248.     mov    di,si        ;save pointer to first argument
  249.     mov    cx,2        ;get second argument
  250.     call    getarg
  251.     cmp    cx,dx        ;lengths equal?
  252.     jne    eq_prim_1    ;no, return 4th
  253.     repe    cmpsb        ;strings equal?
  254.     jne    eq_prim_1    ;no, return 4th.
  255.     mov    cx,3
  256.     jmp    return_arg
  257. eq_prim_1:
  258.     mov    cx,4
  259.     jmp    return_arg
  260.  
  261.  
  262. ne_prim:
  263.     call    getarg1        ;get the first argument
  264.     mov    dx,cx        ;save size of first argument
  265.     mov    di,si        ;save pointer to first argument
  266.     mov    cx,2        ;get second argument
  267.     call    getarg
  268.     cmp    cx,dx        ;lengths equal?
  269.     jne    ne_prim_1    ;no, return 3rd
  270.     repe    cmpsb        ;strings equal?
  271.     jne    ne_prim_1    ;no, return 3rd.
  272.     mov    cx,4
  273.     jmp    return_arg
  274. ne_prim_1:
  275.     mov    cx,3
  276.     jmp    return_arg
  277.  
  278.  
  279. nc_prim:
  280.     call    getarg1
  281.     di_points_fbgn
  282.     mov    ax,cx
  283.     jmp    return_number
  284.  
  285.  
  286. db_prim:
  287.     int    3
  288.     jmp    return_null
  289.  
  290.  
  291. ct_prim:
  292. ;Mon Nov 21 11:31:54 1983
  293.     call    getarg1_filename    ;get the filename.
  294.     jz    ct_prim_1
  295.  
  296.     mov    dx,offset filename2
  297.     mov    ah,1ah
  298.     int    21h
  299.  
  300.     mov    dx,si            ;filename in dx for find_first.
  301.     mov    ah,4eh            ;find first matching file
  302.     mov    cx,10h            ;find subdirs, too.
  303.     int    21h
  304.     jnc    ct_prim_3        ;go if we found it.
  305.     jmp    return_null
  306.  
  307. ct_prim_1:
  308.     mov    ah,2ch            ;get hhmm into si, ssxx into bp, ddd into al.
  309.     int    21h
  310.     mov    si,cx
  311.     mov    bp,dx
  312.  
  313.     mov    ah,2ah            ;get mmdd into dx, yyyy into cx.
  314.     int    21h
  315.  
  316.     di_points_fbgn
  317.  
  318.     call put_ct
  319.  
  320.     jmp    return_tos
  321.  
  322. ct_prim_3:
  323.  
  324.     di_points_fbgn
  325.  
  326.     mov    cx,2
  327.     call    getarg
  328.     push    cx            ; save arg2
  329.     jcxz    ct_prim_6        ;  if no attributes
  330.  
  331.     ;put attributes ADLSHR
  332.  
  333.     mov    al,filename2.find_buf_attr
  334.     and    al,37h            ;only interesting attributes
  335.     mov    ah,0
  336.     mov    bx,2            ;binary
  337.     mov    cx,6
  338.     call    put_number
  339.  
  340. ct_prim_6:
  341.     ;put C time of file modified
  342.  
  343.     mov    ax,filename2.find_buf_time    ;get the hours
  344.     mov    cl,3
  345.     shr    ax,cl
  346.     xor    al,al
  347.     mov    si,ax
  348.  
  349.     mov    ax,filename2.find_buf_time    ;get the minutes
  350.     mov    cl,5
  351.     shr    ax,cl
  352.     and    al,3fh
  353.     xor    ah,ah
  354.     or    si,ax
  355.  
  356.     mov    ax,filename2.find_buf_time    ;get the seconds.
  357.     mov    ah,al
  358.     xor    al,al
  359.     and    ah,1fh
  360.     shl    ah,1                ;but they're twoseconds.
  361.     mov    bp,ax
  362.  
  363. ;we have hhmm in si, ssxx in bp, ddd in al.
  364.  
  365.     mov    ax,filename2.find_buf_date    ;get the months
  366.     mov    cl,3
  367.     shl    ax,cl
  368.     and    ax,0f00h
  369.     mov    dx,ax
  370.  
  371.     mov    ax,filename2.find_buf_date    ;get the days
  372.     and    ax,1fh
  373.     or    dx,ax
  374.  
  375.     mov    ax,filename2.find_buf_date    ;get the year.
  376.     shr    ah,1
  377.     mov    al,ah
  378.     xor    ah,ah
  379.     add    ax,1980
  380.     mov    cx,ax
  381.  
  382.     mov    al,7            ;use '   ' as the day of the week.
  383.  
  384. ;we have mmdd in dx, yyyy in cx.
  385.  
  386.     call put_ct
  387.  
  388.     pop    cx            ; get arg2
  389.     jcxz    ct_prim_4        ;  if no file size
  390.  
  391.     mov    al,' '
  392.     stosb
  393.  
  394.     ;and last, put the file size
  395.  
  396.     mov    ax,word ptr filename2.find_buf_size
  397.     mov    dx,word ptr filename2.find_buf_size+2
  398.     cmp    dx,10000
  399.     jae    ct_prim_4        ;null if too big (655350000 bytes)
  400.     mov    cx,10000
  401.     div    cx
  402.     mov    bx,10            ;old base ten for this
  403.     or    ax,ax            ;short file?
  404.     jz    ct_prim_5
  405.     push    dx
  406.     mov    cx,0
  407.     call    put_number
  408.     pop    ax
  409.     mov    cx,4
  410.     call    put_number
  411.  
  412. ct_prim_4:
  413.     jmp    return_tos
  414.  
  415. ct_prim_5:
  416.     mov    ax,dx
  417.     mov    cx,0
  418.     call    put_number
  419.     jmp    return_tos
  420.  
  421. put_ct:
  422. ;we have hhmm in si, ssxx in bp, ddd in al.
  423. ;we have mmdd in dx, yyyy in cx. And di_points_fbgn
  424.  
  425.     push    cx            ;squirrel yyyy, ssxx, and hhmm away.
  426.     push    bp
  427.     push    si
  428.  
  429. ;we have mmdd in dx, ddd in al.
  430.  
  431.     xor    ah,ah            ;stuff the day of the week.
  432.     add    al,al
  433.     add    al,al
  434.     mov    si,offset day_of_week
  435.     add    si,ax
  436.     movsw
  437.     movsw
  438.  
  439.     mov    al,dh            ;get month (1..12)
  440.     dec    al
  441.  
  442.     xor    ah,ah            ;stuff the month
  443.     add    al,al
  444.     add    al,al
  445.     mov    si,offset months
  446.     add    si,ax
  447.     movsw
  448.     movsw
  449.  
  450.     mov    al,dl            ;pushed as dx (get date)
  451.     mov    bx,10            ;do all conversions in decimal.
  452.     mov    ah,0
  453.     mov    cx,2
  454.     call    put_number
  455.     mov    al,' '
  456.     stosb
  457.  
  458.     pop    bp            ;pushed as cx (get minutes)
  459.     mov    ax,bp            ;we need them in a two-byte register.
  460.  
  461.     mov    al,ah            ;get hours
  462.     mov    ah,0
  463.     mov    cx,2
  464.     call    put_number
  465.     mov    al,":"
  466.     stosb
  467.     mov    ax,bp            ;get minutes back.
  468.     mov    ah,0
  469.     mov    cx,2
  470.     call    put_number
  471.     mov    al,":"
  472.     stosb
  473.     pop    dx            ;get seconds
  474.     mov    al,dh
  475.     mov    ah,0
  476.     mov    cx,2
  477.     call    put_number
  478.     mov    al,' '
  479.     stosb
  480.  
  481.     pop    ax            ;get the year.
  482.     mov    cx,4
  483.     call    put_number
  484.     ret
  485.  
  486.  
  487. ;form primitives
  488.  
  489.  
  490. ds_prim:
  491.     mov    cx,2        ;get data first.
  492.     call    getarg
  493.     mov    dx,cx
  494.     or    dx,8000h    ;set the no-sgap marker.
  495.     mov    di,si
  496.     call    getarg1
  497.     mov    bx,0        ;reset form pointer.
  498.     call    define_form
  499.     jmp    return_null
  500.  
  501.  
  502. mp_prim:
  503.     call    getarg1
  504.     call    find_form
  505.     jc    mp_prim_2
  506.     assume    es:formSeg
  507.     mov    dx,formSeg:[bx].data_length    ;save the count of the form in dx.
  508.     mov    bp,dx
  509.     and    bp,8000h        ;remember the sgap marker.
  510.     and    dx,7fffh        ;get rid of sgap marker.
  511.     lea    di,formSeg:[bx].name_offset
  512.     add    di,formSeg:[bx].name_length    ;save the pointer to the form in di.
  513.     mov    si,fbgn            ;point si at the zeroth arg.
  514.     mov    si,data:[si]        ;point si at the form name.
  515.     mov    si,data:[si]        ;point si at the first argument.
  516.     mov    ah,sgap+1        ;start with sgap 1.
  517. mp_prim_1:
  518.     cmp    si,data:[si]        ;are we pointing at fend?
  519.     je    mp_prim_3
  520.     push    si            ;save pointer to args.
  521.     mov    cx,data:[si]        ;compute length of this arg.
  522.     sub    cx,si
  523.     sub    cx,mark_overhead
  524.     add    si,mark_overhead-1    ;make si=> text of argument.
  525. ;at this point, si,cx => arg; di,dx => form.
  526.     push    di
  527.     push    dx
  528.     jcxz    mp_prim_5    ;ignore null strings.
  529. mp_prim_4:
  530.     call    string_search
  531.     jc    mp_prim_5    ;not found.  Done with this arg.
  532. ;at this point, we have found a string.  We proceed to replace it by
  533. ;the appropriate segment gap.  We have already ensured that the string
  534. ;is at least one character long.
  535.     push    cx        ;preserve cx
  536.     mov    al,ah        ;get the sgap.
  537.     stosb            ;store it.
  538. ;by the way, at this point, the relation (cx <= dx) is always true.
  539.     sub    dx,cx        ;count it, and the ones we're getting rid of.
  540.     dec    cx        ;one less to get rid of.
  541.     mov    al,sgap        ;get rid of the rest of the chars.
  542.     rep    stosb        ;cx may be zero, but it doesn't hurt.
  543.     pop    cx
  544.     xor    bp,bp        ;clear sgap marker -- we found one.
  545.     jmp    mp_prim_4
  546. mp_prim_5:
  547.     pop    dx
  548.     pop    di
  549.     pop    si        ;restore pointer to args.
  550.     mov    si,[si]        ;make it point to next arg.
  551.     inc    ah        ;increment sgap to next arg.
  552.     jmp    mp_prim_1
  553. mp_prim_3:
  554.     cmp    bp,0        ;should we nuke sgaps (were any matches found?)
  555.     jne    mp_prim_9    ;no matches found, preserve sgaps, don't change len.
  556.     mov    si,di        ;now prepare to crunch out the sgap's.
  557.     mov    cx,dx
  558.     mov    dx,di
  559.     jcxz    mp_prim_8
  560. mp_prim_6:
  561.     lods    es:byte ptr 0    ;get a byte from es:
  562.     cmp    al,sgap        ;discard sgaps.
  563.     je    mp_prim_7
  564.     stosb
  565. mp_prim_7:
  566.     loop    mp_prim_6
  567. mp_prim_8:
  568.     sub    di,dx            ;subtract off the base of the string.
  569.     or    di,bp            ;if no match found, preserve original sgap marker.
  570.     mov    formSeg:[bx].data_length,di
  571. mp_prim_9:
  572.     esdata
  573. mp_prim_2:
  574.     jmp    return_null
  575.  
  576.  
  577. nb_prim:
  578.     call    find_arg1
  579.     dsdata
  580.     mov    cx,3
  581.     jc    nb_prim_1
  582.     mov    cx,2
  583. nb_prim_1:
  584.     jmp    return_arg
  585.     assume    ds:data, es:data
  586.  
  587.  
  588. si_prim:
  589.     mov    cx,2            ;get the character we're translating.
  590.     call    getarg
  591.     mov    di,si            ;we need it in di.
  592.     push    di            ;save this as the pointer to what we return.
  593.     jcxz    si_prim_1        ;if no characters, return null.
  594.  
  595.     push    di            ;remember arg2.
  596.     push    cx
  597.     call    find_arg1
  598.     mov    dx,cx
  599.     pop    cx
  600.     pop    di
  601.     jc    si_prim_1        ;go if it doesn't exist.
  602.     mov    bx,si            ;we need the pointer to the string
  603.     xor    ah,ah            ;  in bx.  Get ah=0 so we can compare.
  604. si_prim_2:
  605.     mov    al,es:[di]        ;get the character.
  606.     cmp    ax,dx            ;are there actually that many?
  607.     jae    si_prim_3        ;no - use the old character.
  608.     xlat                ;get the new character.
  609. si_prim_3:
  610.     stosb                ;salt the character back to where we got it.
  611.     loop    si_prim_2
  612. si_prim_1:
  613.     dsdata
  614.     jmp    return_tos
  615.  
  616.  
  617. hk_prim:
  618. ;the hook primitive searches through a list of strings to execute.
  619. ;when it finds a string that exists, it drops through to gs_prim.
  620.     mov    bp,0
  621. hk_prim_1:
  622.     inc    bp            ;pre-increment
  623.     dsdata                ;reload ds as part of loop.
  624.     mov    cx,bp            ;get the number of the form name arg.
  625.     call    getarg            ;get this argument
  626.     jcxz    hk_prim_2        ;give up on the first null argument.
  627.     call    find_string        ;try to find it.
  628.     assume    ds:formSeg
  629.     jc    hk_prim_1        ;go if the function was not found.
  630.     dec    bp
  631.     jmp    short gs_prim_0
  632. hk_prim_2:
  633.     jmp    return_null
  634.     assume    ds:data
  635.  
  636. ;default primitive is the same as the cl primitive, only we start counting
  637. ;  arguments from zero, not one.
  638. dflt:
  639.     mov    cx,0            ;get the number of the form name arg.
  640.     call    find_arg
  641.     mov    bp,-1
  642.     jnc    gs_prim_0        ;go if the function was found.
  643.     mov    si,offset dflta_name
  644.     mov    cx,dflta_len        ;try to find the default active function.
  645.     call    make_active        ;but first make it active.
  646.     je    dflt_1            ;okay, it's really active.
  647.     mov    si,offset dfltn_name
  648.     mov    cx,dfltn_len        ;Ahhhh, it *was* neutral - call dfltn first.
  649. dflt_1:
  650.     call    find_string
  651.     jc    gs_prim_1        ;go if dflt isn't found.
  652.     jmp    short gs_prim_0
  653.  
  654. gs_prim_1:
  655.     dsdata
  656.     jmp    return_null
  657.  
  658. gs_prim:
  659.     call    find_arg1
  660.     jc    gs_prim_1        ;if it doesn't exist, return null.
  661.     mov    bp,1
  662. gs_prim_0:
  663.     assume    ds:formSeg
  664.     jcxz    gs_prim_1        ;if no characters, return null.
  665.     test    formSeg:[bx].data_length,8000h    ;does this have an sgap marker?
  666.     je    gs_prim_6        ;no, there may be some...
  667. ;no sgaps, just return it literally.
  668.     di_points_fbgn
  669.     chk_room_cnt es            ;check for collision
  670.     movmem                ;move all the chars.
  671.     dsdata
  672.     jmp    return_tos
  673. gs_prim_6:
  674.     assume    ds:formSeg
  675.     di_points_fend
  676. gs_prim_2:
  677.     lodsb                ;get char from form.
  678.     or    al,al            ;test it for sgapness
  679.     jge    gs_prim_3        ;go if not sgap
  680.     sub    al,sgap            ;which sgap?
  681.     jz    gs_prim_4        ;ignore sgap0's
  682.     cbw                ;we're going to be counting off ax
  683.     add    ax,bp            ;add in the first arg number.
  684.     push    ds            ;preserve pointer, count of the form
  685.     push    si
  686.     push    cx
  687.     mov    cx,ax
  688.     dsdata
  689.     call    getarg
  690.     chk_room_cnt es
  691.     movmem
  692.     pop    cx            ;restore pointer, count of the form
  693.     pop    si
  694.     pop    ds
  695.     assume    ds:formSeg
  696.     jmp    gs_prim_4
  697. gs_prim_3:
  698.     chk_room es
  699.     stosb
  700. gs_prim_4:
  701.     loop    gs_prim_2
  702.     dsdata
  703.     jmp    return_tos
  704.     assume    ds:data, es:data
  705.  
  706.  
  707. go_prim:
  708.     call    find_arg1
  709.     jc    go_prim_1    ;form not found.
  710.     assume    ds:formSeg
  711.     jcxz    go_prim_2    ;no chars left.
  712.     di_points_fbgn
  713.     movsb            ;no need to check for collision with actptr.
  714.     dec    cx
  715.     jmp    return_form
  716. go_prim_2:
  717.     dsdata
  718.     mov    cx,2
  719.     jmp    return_arg_active
  720. go_prim_1:
  721.     jmp    return_null
  722.     assume    ds:data, es:data
  723.  
  724.  
  725. rs_prim:
  726.     call    find_arg1
  727.     jc    rs_prim_1
  728.     assume    ds:formSeg
  729.     mov    formSeg:[bx].form_pointer,0
  730.     dsdata
  731. rs_prim_1:
  732.     jmp    return_null
  733.     assume    ds:data, es:data
  734.  
  735.  
  736. gn_prim:
  737.     call    find_arg1
  738.     jc    gn_prim_1
  739.     assume    ds:formSeg
  740.     jcxz    gn_prim_2
  741.     push    ds        ;save pointer, count to form.
  742.     push    si
  743.     push    cx
  744.     push    bx
  745.     dsdata
  746.     mov    cx,2        ;get number of chars to call.
  747.     call    get_decimal_arg
  748.     mov    dx,ax        ;save in dx.
  749.     pop    bx
  750.     pop    cx
  751.     pop    si
  752.     pop    ds
  753.     assume    ds:formSeg
  754.     di_points_fbgn
  755.     cmp    dx,cx        ;are we trying to get more than exists?
  756.     jbe    gn_prim_3    ;no - move the requested amount.
  757.     mov    dx,cx        ;yes - truncate the count.
  758. gn_prim_3:
  759.     xchg    dx,cx        ;swap the count remaining and the get count.
  760.     sub    dx,cx        ;dec the count remaining by the get count.
  761.     chk_room_cnt es        ;check for collision
  762.     movmem            ;move all the chars.
  763.     mov    cx,dx        ;return the count remaining in cx.
  764.     jmp    return_form
  765. gn_prim_2:
  766.     dsdata
  767.     mov    cx,3
  768.     jmp    return_arg_active
  769. gn_prim_1:
  770.     jmp    return_null
  771.     assume    ds:data, es:data
  772.  
  773.  
  774.  
  775. fm_prim:
  776.     call    find_arg1
  777.     jc    fm_prim_1    ;if form not found, return null.
  778.     assume    ds:formSeg
  779.     jcxz    fm_prim_2    ;if nothing to search, return two.
  780.     xchgdses
  781.     assume    ds:data, es:formSeg
  782.     push    si
  783.     mov    di,si
  784.     mov    dx,cx
  785.     mov    cx,2
  786.     call    getarg
  787. ;now si,cx => short string, di,dx => long string.
  788.     call    string_search
  789.     jc    fm_prim_3    ;if it's not found, just return arg 3.
  790. ;what we want to do now is to return the string from [tos] to [di],
  791. ;  and advance the form pointer to point after the found string.
  792.     sub    dx,cx        ;dx gets long length - short length.
  793.     pop    si
  794.     mov    cx,di        ;get the number of characters before
  795.     sub    cx,si        ;  the search string.
  796.     xchgdses
  797.     assume    ds:formSeg, es:data
  798.     di_points_fbgn    ;prepare to return a string.
  799.     chk_room_cnt es        ;make sure we have enough room.
  800.     movmem
  801.     mov    cx,dx        ;return_form expects the count in cx.
  802.     jmp    return_form
  803. fm_prim_3:
  804.     add    sp,2        ;get rid of the pointer to the search string.
  805.     assume    es:formSeg    ;because of where we come from above.
  806.     esdata
  807.     mov    cx,3
  808.     jmp    return_arg_active
  809. fm_prim_2:
  810.     assume    ds:formSeg    ;because of where we come from above.
  811.     dsdata
  812.     mov    cx,3
  813.     jmp    return_arg_active
  814. fm_prim_1:
  815.     jmp    return_null
  816.     assume    ds:data, es:data
  817.  
  818.  
  819. ev_prim:
  820.     xor    si,si            ;start at the beginning of the environ.
  821. ev_prim_1:
  822.     mov    di,fbgn
  823.  
  824.     push    si            ;copy in the environ name.
  825.     mov    si,offset environ_name
  826.     mov    cx,environ_name_len
  827.     movmem
  828.     pop    si
  829.  
  830.     push    ds
  831.     mov    ds,phd_seg
  832.     mov    ds,ds:[2ch]
  833. ev_prim_2:
  834.     lodsb
  835.     stosb
  836.     or    al,al
  837.     jne    ev_prim_2
  838.     pop    ds
  839.     mov    cx,di            ;compute the length of it.
  840.     sub    cx,fbgn
  841.     dec    cx            ;don't count the null.
  842.  
  843.     cmp    cx,environ_name_len    ;did we get any at all?
  844.     je    ev_prim_3        ;if none, we're done.
  845.  
  846.     push    si            ;remember the environment pointer.
  847.     mov    di,fbgn            ;make di->entire name.
  848.     mov    si,di            ;make si -> the name.
  849.     mov    al,'='            ;look for the name/data separator.
  850.     repne    scasb
  851.     mov    dx,cx            ;dx (data length) is number of chars left.
  852.     mov    cx,di            ;compute the name length.
  853.     sub    cx,si
  854.     dec    cx            ;don't count the '='.
  855.  
  856. ;define a form.  Enter with:
  857. ;    si => name
  858. ;    cx = name length
  859. ;    di => data
  860. ;    dx = data length
  861. ;    bx = form pointer.
  862.  
  863.     xor    bx,bx
  864.     call    define_form
  865.     pop    si
  866.     jmp    ev_prim_1
  867. ev_prim_3:
  868.     mov    ah,30h            ;get the dos version.
  869.     int    21h
  870.     cmp    al,3            ;the full path is only in dos 3.0.
  871.     jb    ev_prim_4
  872.  
  873.     add    si,2            ;point to the pathname.
  874.     mov    di,fbgn
  875.     push    ds
  876.     mov    ds,phd_seg
  877.     mov    ds,ds:[2ch]
  878. ev_prim_5:
  879.     lodsb
  880.     stosb
  881.     or    al,al
  882.     jne    ev_prim_5
  883.     pop    ds
  884.     mov    dx,di            ;compute the length of it.
  885.     sub    dx,fbgn
  886.     dec    dx            ;don't count the null.
  887.  
  888.     mov    di,fbgn            ;restore di again.
  889.     mov    si,offset fullpath_name
  890.     mov    cx,fullpath_len
  891.     xor    bx,bx
  892.     call    define_form
  893.  
  894. ev_prim_4:
  895.     mov    di,fbgn
  896.     mov    si,80h
  897.     push    ds
  898.     mov    ds,phd_seg
  899.     lodsb                ;get the line length.
  900.     mov    dl,al
  901.     mov    dh,0
  902.     mov    cx,dx            ;put it where movs can destroy it.
  903.     movmem
  904.     pop    ds
  905.  
  906.     mov    di,fbgn            ;restore di again.
  907.     mov    si,offset runline_name
  908.     mov    cx,runline_len
  909.     xor    bx,bx
  910.     call    define_form
  911.  
  912.     mov    ax,3700h        ;get the switchar.
  913.     int    21h
  914.  
  915.     mov    di,fbgn
  916.     mov    [di],dl            ;store the switchar.
  917.     mov    dx,1            ;set the data length.
  918.  
  919.     mov    si,offset switchar_name
  920.     mov    cx,switchar_len
  921.     xor    bx,bx
  922.     call    define_form
  923.  
  924. ;define env.SCREEN to be the original screen.
  925.     mov    dl,max_screen_line    ;copy page one to active string.
  926.     add    dl,2
  927.     mov    cl,dl            ;remember how many lines to do.
  928.     xor    ch,ch
  929.  
  930.     mov    di,fbgn
  931. ev_prim_6:
  932.     push    cx
  933.     call    read_chars
  934.     mov    es:[di],LINENEW        ;add a newline to the chars.
  935.     add    di,2
  936.     inc    dl
  937.     pop    cx
  938.     loop    ev_prim_6
  939.  
  940.     mov    dx,di
  941.     mov    di,fbgn            ;restore di again.
  942.     sub    dx,di            ;make dx = length of data.
  943.     mov    si,offset screen_name
  944.     mov    cx,screen_len
  945.     xor    bx,bx
  946.     call    define_form
  947.  
  948.     jmp    return_null
  949.  
  950.  
  951.     ret
  952.  
  953.  
  954. ls_prim:
  955.     di_points_fend
  956.     call    getarg1            ;get seperator and save it.
  957.     mov    bp,si            ;store the pointer to arg1 in bp
  958.     mov    dx,cx            ;store the size of arg1 in dx
  959.     mov    cx,2            ;get the form prefix.
  960.     call    getarg
  961.     mov    form_prefix_len,cx
  962.     mov    form_prefix_ptr,si
  963.     call    first_form        ;get a pointer to the first form.
  964. ;during the execution of this loop, bp->, dx = arg1, es:bx->forms.
  965. ls_prim_1:
  966.     assume    es:formSeg
  967.     je    ls_prim_2        ;no more forms, we're done.
  968.     lea    si,formSeg:[bx].name_offset    ;get the name pointer.
  969.     mov    cx,form_prefix_len
  970.     jcxz    ls_prim_3        ;zero prefixes match anything.
  971.     cmp    cx,formSeg:[bx].name_length    ;is prefix length>name length?
  972.     ja    ls_prim_4        ;yes - prefix can't match.
  973.     push    di            ;save the source pointers.
  974.     push    si
  975.     mov    di,si
  976.     mov    si,form_prefix_ptr
  977.     repe    cmpsb            ;compare the prefix to the form name.
  978.     pop    si
  979.     pop    di
  980.     jne    ls_prim_4        ;the prefixes didn't match - ignore it.
  981. ls_prim_3:
  982.     mov    cx,formSeg:[bx].name_length    ;get the name length
  983.     xchgdses
  984.     assume    ds:formSeg, es:data
  985.     chk_room_cnt es
  986.     movmem                ;move the name in.
  987.     dsdata
  988.     mov    si,bp            ;get the pointer to arg1.
  989.     mov    cx,dx            ;get the size of arg1.
  990.     chk_room_cnt
  991.     movmem                ;move it in.
  992. ls_prim_4:
  993.     call    next_form
  994.     jmp    ls_prim_1        ;and continue.
  995. ls_prim_2:
  996.     esdata
  997.     jmp    return_tos
  998.     assume    ds:data, es:data
  999.  
  1000.  
  1001. es_prim:
  1002.     mov    si,fbgn        ;point si at "es".
  1003.     mov    si,[si]        ;point si at the first arg.
  1004. es_prim_1:
  1005.     cmp    si,[si]        ;are we pointing at fend?
  1006.     je    es_prim_3
  1007.     push    si        ;save pointer to args.
  1008.     mov    cx,[si]        ;compute length of this arg.
  1009.     sub    cx,si
  1010.     sub    cx,mark_overhead
  1011.     add    si,mark_overhead-1    ;make si=> text of argument.
  1012.     call    find_form    ;try to find this form.
  1013.     jc    es_prim_2    ;go if it didn't exist.
  1014.     assume    es:formSeg
  1015.     call    delete_form    ;delete the form if it did exist.
  1016.     esdata
  1017. es_prim_2:
  1018.     pop    si        ;restore pointer to args.
  1019.     mov    si,[si]        ;make it point to next arg.
  1020.     jmp    es_prim_1
  1021. es_prim_3:
  1022.     jmp    return_null
  1023.     assume    ds:data, es:data
  1024.  
  1025.  
  1026. sl_prim:
  1027.     call    getarg1_filename
  1028.     mov    dx,si
  1029.     mov    cx,0
  1030.     mov    ah,3ch            ;create file.
  1031.     int    21h
  1032.     mov    bx,ax            ;remember the handle.
  1033.     mov    al,2
  1034.     jc    sl_prim_4
  1035.     mov    si,fbgn            ;point si at the zeroth arg.
  1036.     mov    si,[si]            ;point si at the form name.
  1037.     mov    si,[si]            ;point si at the first search string.
  1038. sl_prim_1:
  1039.     cmp    si,[si]            ;are we pointing at fend?
  1040.     je    sl_prim_3
  1041.     push    si            ;save pointer to args.
  1042.     mov    cx,[si]            ;compute length of this arg.
  1043.     sub    cx,si
  1044.     sub    cx,mark_overhead
  1045.     add    si,mark_overhead-1    ;make si=> text of argument.
  1046.     push    bx
  1047.     call    find_form
  1048.     mov    di,bx            ;remember where the form is.
  1049.     pop    bx
  1050.     jc    sl_prim_2        ;go if it isn't there.
  1051.     xchgdses
  1052.     assume    ds:formSeg, es:data
  1053.     mov    dx,di
  1054.     mov    cx,formSeg:[di].form_length
  1055.     mov    ah,40h            ;write to a file
  1056.     int    21h
  1057.     dsdata
  1058.     jnc    sl_prim_2        ;no problem.
  1059.     mov    ah,3eh            ;disk full - close the file.
  1060.     int    21h
  1061.     mov    dx,offset filename    ;delete the file.
  1062.     mov    ah,41h
  1063.     int    21h
  1064.     mov    al,1
  1065.     jmp    short sl_prim_4
  1066. sl_prim_2:
  1067.     pop    si        ;restore pointer to args.
  1068.     mov    si,[si]        ;make it point to next arg.
  1069.     esdata
  1070.     jmp    sl_prim_1
  1071. sl_prim_3:
  1072.  
  1073.     mov    ah,3eh        ;close the file.
  1074.     int    21h
  1075.     mov    al,0        ;no problem.
  1076. sl_prim_4:
  1077.     mov    bx,offset write_errors
  1078.     jmp    return_string
  1079.     assume    ds:data, es:data
  1080.  
  1081.  
  1082. ll_prim:
  1083. ;Note that information about the structure 'form' is hard-coded into the
  1084. ;  next routine.  We assume that 'form_length' is only two bytes long,
  1085. ;  and occurs at the beginning of the structure.
  1086.     call    getarg1_filename
  1087.     mov    dx,si
  1088.     mov    ax,3d00h        ;open file for reading.
  1089.     int    21h
  1090.     mov    bx,ax            ;remember the handle.
  1091.     mov    al,2
  1092.     jc    ll_prim_4
  1093.     mov    cx,0            ;nothing in the buffer at present.
  1094.     mov    si,fend            ;set the buffer pointer.
  1095. ll_prim_read:
  1096. ;si -> buffer (=fend), cx = count left in buffer.
  1097.     mov    di,fend            ;now move the rest of the buffer down
  1098.     push    cx            ;  to fend.
  1099.     movmem
  1100.     pop    cx
  1101.     mov    si,fend            ;now point to the rest of the buffer.
  1102.  
  1103.     mov    dx,di            ;set disk transfer address.
  1104.  
  1105.     push    cx
  1106.     mov    cx,data_bottop        ;add in the free space.
  1107.     sub    cx,di            ;subtract off the buffer address.
  1108.     mov    ah,3fh            ;read from a file.
  1109.     int    21h
  1110.     pop    cx
  1111.     jc    ll_prim_5        ;close the file - trouble reading.
  1112.     or    ax,ax            ;did we hit eof?
  1113.     je    ll_prim_6        ;yes - we're done.
  1114.     add    cx,ax            ;add to the count the amount we read.
  1115.     add    dx,ax
  1116.     mov    data_topbot,dx        ;remember the highest location that we use.
  1117.  
  1118.     cmp    cx,[si]            ;do we have enough room to read this in?
  1119.     jb    ll_prim_3        ;no - report nomem.
  1120. ll_prim_1:
  1121. ;si -> buffer, cx = count left in buffer.
  1122.     cmp    word ptr [si],0        ;is this the end of the library?
  1123.     je    ll_prim_6        ;yes - we're all done.
  1124.  
  1125.     push    bx            ;define this form.
  1126.     push    cx
  1127.     push    si
  1128.     mov    cx,[si].name_length
  1129.     mov    dx,[si].data_length
  1130.     mov    bx,[si].form_pointer
  1131.     lea    si,[si].name_offset
  1132.     mov    di,si
  1133.     add    di,cx            ;or [si].name_length, but cx is cheaper.
  1134.     call    define_form
  1135.     pop    si
  1136.     pop    cx
  1137.     pop    bx
  1138.  
  1139.     sub    cx,[si]            ;remove this one from the buffer.
  1140.     add    si,[si]            ;skip past this one.
  1141.  
  1142.     cmp    cx,2            ;if not enough, we need to read again.
  1143.     jb    ll_prim_read
  1144.     cmp    cx,[si]            ;do we have that many bytes?
  1145.     jb    ll_prim_read        ;if not enough, we need to read again.
  1146.  
  1147.     jmp    ll_prim_1
  1148. ll_prim_6:
  1149.     mov    ah,3eh            ;close the file.
  1150.     int    21h
  1151.     mov    al,0            ;all ok.
  1152.     jmp    ll_prim_4        ;we destroyed the active string.
  1153. ll_prim_3:
  1154.     mov    ah,3eh            ;close the file.
  1155.     int    21h
  1156.     call    nomem
  1157. ll_prim_5:
  1158.     mov    ah,3eh            ;close the file.
  1159.     int    21h
  1160.     mov    al,3            ;read error.
  1161. ll_prim_4:
  1162.     mov    bx,offset read_errors
  1163.     jmp    return_string
  1164.  
  1165.  
  1166. ad_prim:
  1167.     call    get_math
  1168.     add    ax,bx
  1169.     jmp    return_number_si
  1170.  
  1171.  
  1172. su_prim:
  1173.     call    get_math
  1174.     sub    ax,bx
  1175.     jmp    return_number_si
  1176.  
  1177.  
  1178. ml_prim:
  1179.     call    get_math
  1180.     imul    bx
  1181.     jmp    return_number_si
  1182.  
  1183.  
  1184. dv_prim:
  1185.     call    get_math
  1186.     or    bx,bx
  1187.     je    dv_prim_1
  1188.     cwd
  1189.     idiv    bx
  1190. dv_prim_1:
  1191.     jmp    return_number_si
  1192.  
  1193.  
  1194. md_prim:
  1195.     call    get_math
  1196.     or    bx,bx
  1197.     je    md_prim_1
  1198.     cwd
  1199.     idiv    bx
  1200.     mov    ax,dx
  1201. md_prim_1:
  1202.     jmp    return_number_si
  1203.  
  1204.  
  1205. and_prim:
  1206.     call    get_math
  1207.     and    ax,bx
  1208.     jmp    return_number_si
  1209.  
  1210.  
  1211. or_prim:
  1212.     call    get_math
  1213.     or    ax,bx
  1214.     jmp    return_number_si
  1215.  
  1216.  
  1217. xor_prim:
  1218.     call    get_math
  1219.     xor    ax,bx
  1220.     jmp    return_number_si
  1221.  
  1222.  
  1223. gr_prim:
  1224.     call    get_math
  1225.     mov    cx,3
  1226.     cmp    ax,bx
  1227.     jg    gr_prim_1
  1228.     mov    cx,4
  1229. gr_prim_1:
  1230.     jmp    return_arg
  1231.  
  1232.  
  1233. st_prim:
  1234. ;set the syntax table.
  1235.     call    find_arg1
  1236.     assume    ds:formSeg
  1237.     jnc    st_prim_1
  1238.     mov    bx,NIL            ;if form not found, use NIL.
  1239. st_prim_1:
  1240.     call    store_syntax_table
  1241.     dsdata
  1242.     jmp    return_null
  1243.  
  1244.  
  1245. ;primitive declarations
  1246.     public    st_prim
  1247.     public    dflt
  1248.     public    hl_prim
  1249.     public    eq_prim
  1250.     public    ne_prim
  1251.     public    nc_prim
  1252.     public    db_prim
  1253.     public    ct_prim
  1254. ;forms
  1255.     public    ds_prim
  1256.     public    mp_prim
  1257.     public    gs_prim
  1258.     public    hk_prim
  1259.     public    go_prim
  1260.     public    gn_prim
  1261.     public    rs_prim
  1262.     public    fm_prim
  1263.     public    ev_prim
  1264.     public    ls_prim
  1265.     public    es_prim
  1266.     public    sl_prim
  1267.     public    ll_prim
  1268.     public    nb_prim
  1269.     public    si_prim
  1270. ;math
  1271.     public    ad_prim
  1272.     public    su_prim
  1273.     public    ml_prim
  1274.     public    dv_prim
  1275.     public    md_prim
  1276.     public    and_prim
  1277.     public    or_prim
  1278.     public    xor_prim
  1279.     public    gr_prim
  1280.  
  1281. ;form subroutines
  1282.     extrn    define_form: near
  1283.     extrn    delete_form: near
  1284. ;delete_form deletes the form pointed to by ds:bx.
  1285.  
  1286. ;store_syntax_table stores the form in es:bx as the syntax table.
  1287.     extrn    store_syntax_table: near
  1288.  
  1289.     extrn    first_form: near    ;returns es:bx ->first form.
  1290.     extrn    next_form: near        ;returns es:bx ->next form, zr if none.
  1291.  
  1292.     extrn    find_form: near
  1293. ;find_form returns bx pointing to the form whose name is pointed to by si.
  1294. ;    The length of the form name is given in cx.
  1295. ;    If the form doesn't exist, cy is set, otherwise cy is clear.
  1296. ;    A pointer to the form header is returned in es:bx
  1297.  
  1298.     extrn    find_arg1: near
  1299. ;find_arg1 returns bx pointing to the form whose name is given in
  1300. ;    arg1.  If the form doesn't exist, cy is set, otherwise cy is clear.
  1301. ;    ds:si points to the form data after the form pointer, and cx is the
  1302. ;    number of chars after the form pointer.
  1303.  
  1304.     extrn    find_arg: near
  1305. ;find_arg returns bx pointing to the form whose name is given in
  1306. ;    the arg specified by cx.  If the form doesn't exist, cy is
  1307. ;    set, otherwise cy is clear.  ds:si points to the form data
  1308. ;    after the form pointer, and cx is the number of chars after
  1309. ;    the form pointer.
  1310.  
  1311.  
  1312.     extrn    find_string: near
  1313. ;find_string returns bx pointing to the form whose name is specified by si,cx.
  1314. ;    If the form doesn't exist, cy is set, otherwise cy is clear.  ds:si
  1315. ;    points to the form data after the form pointer, and cx is the number
  1316. ;    of chars after the form pointer.
  1317.  
  1318.  
  1319. ;utility subroutines
  1320.  
  1321.  
  1322.     public    get_math
  1323. get_math:
  1324. ;exit with ax=first number, bx=second number, si->first arg, di->first number.
  1325.     mov    cx,2
  1326.     call    get_decimal_arg
  1327.     push    ax
  1328.     call    getarg1
  1329.     push    si
  1330.     call    get_decimal
  1331.     mov    di,si
  1332.     pop    si
  1333.     pop    bx        ;pushed as ax
  1334.     ret
  1335.  
  1336.  
  1337.     public    get_decimal_arg1
  1338. get_decimal_arg1:
  1339.     mov    cx,1
  1340. ;fall through
  1341.     public    get_decimal_arg
  1342. get_decimal_arg:
  1343.     call    getarg
  1344. ;fall through
  1345.     public    get_decimal
  1346. get_decimal:
  1347.     mov    bx,10
  1348. ;fall through
  1349.     public    get_number
  1350. get_number:
  1351. ;enter with si,cx => string containing trailing number, bx=base to convert
  1352. ;  number in.  Return number in ax, si => start of digit string.
  1353.     add    si,cx
  1354.     push    cx
  1355. get_number_1:
  1356.     dec    si
  1357.     mov    al,[si]
  1358.     sub    al,"0"            ;between 0 and "9"?
  1359.     jb    get_number_2        ;no - can't be a digit.
  1360.     cmp    al,"9"-"0"        ;between "0" and "9"?
  1361.     jbe    get_number_6        ;yes - must be a digit.
  1362.     cmp    al,"a"-"0"
  1363.     jb    get_number_8
  1364.     sub    al,"a"-"A"
  1365. get_number_8:
  1366.     cmp    al,"A"-"0"        ;between "A" and "9"?
  1367.     jb    get_number_2        ;yes - can't be a digit.
  1368.     sub    al,"A"-("0"+10)        ;convert "A" to 10
  1369. get_number_6:
  1370.     cmp    al,bl            ;a legal digit in the desired base?
  1371.     jae    get_number_2        ;no.
  1372.     loop    get_number_1
  1373.     dec    si            ;setup for pre-increment.
  1374. get_number_2:
  1375.     mov    dx,cx
  1376.     pop    cx            ;restore count.
  1377.     sub    cx,dx            ;get the actual count of chars into cx.
  1378.     push    dx            ;remember the number of characters left.
  1379.     inc    si
  1380.     push    si            ;save a copy of the start of the number.
  1381.     mov    ax,0            ;initially zero.
  1382. ;at this point, si => first digit, cx = count of digits to convert.
  1383.     jcxz    get_number_4        ;if no more chars, we're done.
  1384. get_number_3:
  1385.     mul    bx
  1386.     mov    dx,ax
  1387.     lodsb                ;ax = new ASCII digit.
  1388.     sub    al,"0"            ;make it a number.
  1389.     cmp    al,"9"-"0"
  1390.     jbe    get_number_7
  1391.     cmp    al,"a"-"0"
  1392.     jb    get_number_9
  1393.     sub    al,"a"-"A"
  1394. get_number_9:
  1395.     sub    al,"A"-("0"+10)
  1396. get_number_7:
  1397.     cbw                ;make it a word.
  1398.     add    ax,dx            ;and add in the old value.
  1399.     loop    get_number_3
  1400. get_number_4:
  1401.     pop    si
  1402.     pop    dx
  1403.     or    dx,dx            ;did we use up all the characters?
  1404.     je    get_number_5        ;yes - don't look for a minus sign.
  1405.     cmp    byte ptr -1[si],"-"
  1406.     jne    get_number_5
  1407.     dec    si
  1408.     neg    ax
  1409. get_number_5:
  1410.     ret
  1411.  
  1412.  
  1413. return_number_si:
  1414.     push    si
  1415.     public    return_number
  1416. return_number:
  1417. ;enter with di => place to put string, tos => start of string,
  1418. ;  ax=number.
  1419.     mov    cx,0            ;use only as many digits as is needed.
  1420.     mov    bx,10
  1421.     call    put_number
  1422.     jmp    return_tos
  1423.  
  1424.  
  1425.     public    put_number
  1426. put_number:
  1427. ;enter with di => place to put string, ax = number, cx=minimum number of digits
  1428. ;  bx=base to convert number to.
  1429.     or    ax,ax
  1430.     jge    put_number_1
  1431.     neg    ax
  1432.     mov    byte ptr [di],"-"
  1433.     inc    di
  1434. put_number_1:
  1435.     call    one_digit
  1436.     ret
  1437.  
  1438.  
  1439. one_digit:
  1440.     jcxz    one_digit_3
  1441.     dec    cx
  1442. one_digit_3:
  1443.     xor    dx,dx        ;unsigned number.
  1444.     div    bx
  1445.     push    dx
  1446.     or    ax,ax
  1447.     jnz    one_digit_1    ;if more digits, do them.
  1448.     jcxz    one_digit_2    ;if count is zero, don't do next digit.
  1449. ;we get here if we have more digits to do, or we have more leading
  1450. ; zeroes to place.
  1451. one_digit_1:
  1452.     call    one_digit
  1453. one_digit_2:
  1454.     pop    ax        ;pushed as dx
  1455.     add    al,"0"
  1456.     cmp    al,"9"
  1457.     jbe    one_digit_4
  1458.     add    al,"A"-("9"+1)    ;the digit above "9" becomes an "A".
  1459. one_digit_4:
  1460.     chk_room
  1461.     stosb
  1462.     ret
  1463.  
  1464.  
  1465. string_search:
  1466.  
  1467.     if    0
  1468.  
  1469. ;enter with si,cx => short string, es:di,dx => long string.
  1470. ;exit with nc if string was found, es:di,dx => position found.
  1471. ;exit with cy if string was not found.
  1472.     jcxz    string_search_3    ;zero length strings are found immediately
  1473. ;we can get into trouble if cx = 0 after this point.
  1474. string_search_1:
  1475.     cmp    dx,cx
  1476.     jb    string_search_2
  1477.     push    si    ;preserve all the registers.
  1478.     push    di
  1479.     push    cx
  1480.     repe    cmpsb
  1481.     pop    cx
  1482.     pop    di
  1483.     pop    si
  1484.     je    string_search_3
  1485.     dec    dx
  1486.     inc    di
  1487.     jmp    string_search_1
  1488. string_search_3:
  1489.     clc
  1490.     ret
  1491. string_search_2:
  1492.     stc
  1493.     ret
  1494.  
  1495.     else
  1496.  
  1497. ;enter with si,cx => short string, es:di,dx => long string.
  1498. ;exit with nc if string was found, es:di,dx => position found.
  1499. ;exit with cy if string was not found.
  1500. ;preserve si,cx, ah.
  1501.     push    bx
  1502.     jcxz    string_search_3        ;zero length strings are found immediately
  1503.     mov    bx,cx            ;save short string length.
  1504.     mov    cx,dx            ;get long string length.
  1505.     mov    dx,si            ;save short string pointer.
  1506.     dec    bx
  1507.     sub    cx,bx            ;this many fewer chars to look at.
  1508.     jb    string_search_2        ;"short" string isn't really shorter.
  1509. string_search_1:
  1510.     jcxz    string_search_2        ;no chars to look at.
  1511.     mov    si,dx
  1512.     lodsb                ;get the first char.
  1513.     repne    scasb            ;look for the first char.
  1514.     jnz    string_search_2        ;we didn't find it.
  1515.     push    cx            ;save the short length length
  1516.     push    di            ;save the long position
  1517.     mov    cx,bx            ;get cx=short string length - 1.
  1518.     or    cx,cx            ;if cx is zero, we match.
  1519.     repe    cmpsb            ;is this it?
  1520.     pop    di            ;restore the long position
  1521.     pop    cx            ;restore the short length
  1522.     jne    string_search_1        ;no match - try at next position.
  1523.  
  1524.     mov    si,dx            ;restore short pointer.
  1525.     dec    di            ;make di point to the first char again.
  1526.     inc    cx            ;and have cx be the number of chars left.
  1527.  
  1528.     add    cx,bx            ;restore the original count.
  1529.     mov    dx,cx            ;return the remaining count in dx.
  1530.  
  1531.     mov    cx,bx            ;restore short count
  1532.     inc    cx            ;restore count's original value.
  1533. string_search_3:
  1534.     pop    bx
  1535.     clc
  1536.     ret
  1537. string_search_2:
  1538.     mov    si,dx            ;restore short pointer.
  1539.     mov    cx,bx            ;restore search count
  1540.     inc    cx            ;restore count's original value.
  1541.     pop    bx
  1542.     stc
  1543.     ret
  1544.  
  1545.     endif
  1546.  
  1547.  
  1548.     public    getarg1_filename
  1549. getarg1_filename:
  1550.     mov    cx,1
  1551.     public    getarg_filename
  1552. getarg_filename:
  1553. ;return si ->filename, zr if filename is null.
  1554.     call    getarg
  1555.     mov    di,offset filename
  1556.     movmem
  1557.     xor    al,al
  1558.     stosb
  1559.     mov    si,offset filename
  1560.     cmp    [si],al
  1561.     ret
  1562.  
  1563.  
  1564.     extrn    getarg1: near
  1565. ;getarg1 returns si -> the first argument.  cx is set to the size
  1566. ;    of the first argument.
  1567.  
  1568.     extrn    getarg: near
  1569. ;getarg returns si -> the argument given in cx.  cx is set to the size
  1570. ;    of the argument.
  1571.  
  1572. code    ends
  1573.  
  1574.     end    init
  1575.  
  1576.